package com.fount4j.generator.introspect;

import com.fount4j.generator.config.TableConfig;
import com.fount4j.generator.context.GeneratorContext;
import com.fount4j.generator.exception.GenerateException;
import com.fount4j.generator.info.ColumnInfo;
import com.fount4j.generator.info.TableInfo;
import com.fount4j.generator.util.JdbcUtils;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 解析器
 *
 * @author Morven 2016/12/21
 */
public class Introspector {

    /**
     * 解析数据库表
     *
     * @param context  解析器上下文
     * @param metaData 数据库元数据
     */
    public void introspectTable(GeneratorContext context, DatabaseMetaData metaData) {
        TableConfig tableConfig = context.getTableConfig();
        TableInfo tableInfo = null;
        ResultSet rs = null;
        try {
            rs = metaData.getTables(tableConfig.getCatalog(), tableConfig.getSchema(), tableConfig.getName(), null);
            if (rs.next()) {
                tableInfo = new TableInfo();
                context.setTableInfo(tableInfo);
                tableInfo.setColumns(getColumns(context, metaData, tableConfig));
                tableInfo.setRealName(rs.getString("TABLE_NAME"));
                tableInfo.setRemarks(rs.getString("REMARKS"));
                introspectPrimaryKeyColumns(tableInfo, metaData, tableConfig);
                context.getEntityIntrospector().introspect(context);
                context.getDaoIntrospector().introspect(context);
                context.getMapperIntrospector().introspect(context);
            } else {
                throw new GenerateException("未获取到[" + tableConfig.getName() + "]表结构信息");
            }
        } catch (SQLException e) {
            throw new GenerateException("解析数据库表出错: " + tableConfig.getName(), e);
        } finally {
            JdbcUtils.close(rs);
        }
    }

    protected void introspectPrimaryKeyColumns(TableInfo tableInfo, DatabaseMetaData metaData,
            TableConfig tableConfig) {
        ResultSet rs = null;
        try {
            rs = metaData.getPrimaryKeys(tableConfig.getCatalog(), tableConfig.getSchema(), tableConfig.getName());
            while (rs.next()) {
                String columnName = rs.getString("COLUMN_NAME"); //$NON-NLS-1$
                for (ColumnInfo columnInfo : tableInfo.getColumns()) {
                    if (columnInfo.getRealName().equals(columnName)) {
                        columnInfo.setPrimaryKey(true);
                        tableInfo.getPrimaryKeyColumns().add(columnInfo);
                    }
                }
            }
        } catch (SQLException e) {
            throw new GenerateException("解析数据库表主键出错: " + tableConfig.getName(), e);
        } finally {
            JdbcUtils.close(rs);
        }
    }

    protected List<ColumnInfo> getColumns(GeneratorContext context, DatabaseMetaData metaData,
            TableConfig tableConfig) {
        List<ColumnInfo> columns = new ArrayList<>();
        ResultSet rs = null;
        try {
            rs = metaData.getColumns(tableConfig.getCatalog(), tableConfig.getSchema(), tableConfig.getName(), "%");
            boolean supportsIsAutoIncrement = false;
            ResultSetMetaData rsmd = rs.getMetaData();
            int colCount = rsmd.getColumnCount();
            for (int i = 1; i <= colCount; i++) {
                if ("IS_AUTOINCREMENT".equals(rsmd.getColumnName(i))) { //$NON-NLS-1$
                    supportsIsAutoIncrement = true;
                }
            }

            while (rs.next()) {
                String realName = rs.getString("COLUMN_NAME"); //$NON-NLS-1$
                ColumnInfo columnInfo = new ColumnInfo();

                columnInfo.setTableAlias(tableConfig.getAlias());
                columnInfo.setDbType(rs.getInt("DATA_TYPE")); //$NON-NLS-1$
                columnInfo.setDbTypeName(rs.getString("TYPE_NAME")); //$NON-NLS-1$
                columnInfo.setLen(rs.getInt("COLUMN_SIZE")); //$NON-NLS-1$
                columnInfo.setRealName(realName);
                columnInfo.setNullable(rs.getInt("NULLABLE") == DatabaseMetaData.columnNullable); //$NON-NLS-1$
                columnInfo.setScale(rs.getInt("DECIMAL_DIGITS")); //$NON-NLS-1$
                columnInfo.setRemarks(rs.getString("REMARKS")); //$NON-NLS-1$
                columnInfo.setDefaultValue(rs.getString("COLUMN_DEF")); //$NON-NLS-1$

                if (supportsIsAutoIncrement) {
                    columnInfo.setAutoIncrement(
                            "YES".equals(rs.getString("IS_AUTOINCREMENT"))); //$NON-NLS-1$ //$NON-NLS-2$
                }
                context.getColumnIntrospector().introspectColumn(context, columnInfo);
                columns.add(columnInfo);
            }
        } catch (SQLException e) {
            throw new GenerateException("解析表字段出错", e);
        } finally {
            JdbcUtils.close(rs);
        }
        return columns;
    }

}
